// app/src/main/cpp/native-lib.cpp
#include <jni.h>
#include <string>
#include "backward.h"
#include <android/log.h>
// 定义日志标签和日志级别宏（可选但推荐）
#define LOG_TAG "NativeSurvey"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

// 正确示例
extern "C" JNIEXPORT jstring JNICALL
Java_com_auto_survey_activity_geosurv_backward_jni_MyNativeClass_stringFromJNI(JNIEnv* env, jobject) {
    return env->NewStringUTF("Hello from C++");
}

extern "C"
JNIEXPORT jobject JNICALL
Java_com_auto_survey_activity_geosurv_backward_jni_MyNativeClass_calculateResectionToJNI(
        JNIEnv *env, jobject /* this */, jobject points, jobject observations, jint size) {

    LOGI("JNI方法被调用，控制点数量: %d", size);  // 打印输入参数

    // 1. 检查size参数有效性（至少需要3个控制点）
    if (size < 3) {
        env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"),
                      "控制点数量必须不少于3个");

        LOGE("控制点数量必须不少于3个");  // 打印输入参数
        return nullptr;
    }

    // 2. 获取Java List操作方法
    jclass listClass = env->GetObjectClass(points);
    jmethodID listGet = env->GetMethodID(listClass, "get", "(I)Ljava/lang/Object;");
    if (listGet == nullptr) {
        env->ThrowNew(env->FindClass("java/lang/NoSuchMethodError"),
                      "List.get()方法未找到");

        LOGE("List.get()方法未找到");
        return nullptr;
    }

    // 3. 转换Java Point列表为C结构体数组
    Point* controlPoints = (Point*)malloc(size * sizeof(Point));
    if (controlPoints == nullptr) {
        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"),
                      "控制点数组内存分配失败");

        LOGE("控制点数组内存分配失败");
        return nullptr;
    }

    // 3.1 获取Kotlin Point类信息
    jclass pointClass = env->FindClass("com/auto/survey/activity/geosurv/backward/entity/Point");
    if (pointClass == nullptr) {
        env->ThrowNew(env->FindClass("java/lang/ClassNotFoundException"),
                      "Point类未找到");
        LOGE("Point类未找到");
        free(controlPoints);
        return nullptr;
    }

    jfieldID pointXField = env->GetFieldID(pointClass, "x", "D");
    jfieldID pointYField = env->GetFieldID(pointClass, "y", "D");
    jfieldID pointZField = env->GetFieldID(pointClass, "z", "D");
    if (pointXField == nullptr || pointYField == nullptr) {
        env->ThrowNew(env->FindClass("java/lang/NoSuchFieldError"),
                      "Point类字段未找到");
        LOGE("Point类字段未找到");
        free(controlPoints);
        env->DeleteLocalRef(pointClass);
        return nullptr;
    }

    // 3.2 填充控制点数据
    LOGI("填充控制点数据");
    for (int i = 0; i < size; i++) {
        jobject pointObj = env->CallObjectMethod(points, listGet, i);
        if (pointObj == nullptr) {
            env->ThrowNew(env->FindClass("java/lang/IndexOutOfBoundsException"),
                          "控制点列表访问越界");
            LOGE("控制点列表访问越界");
            free(controlPoints);
            env->DeleteLocalRef(pointClass);
            return nullptr;
        }



        controlPoints[i].x = env->GetDoubleField(pointObj, pointXField);
        controlPoints[i].y = env->GetDoubleField(pointObj, pointYField);
        controlPoints[i].z = env->GetDoubleField(pointObj, pointZField);



        env->DeleteLocalRef(pointObj); // 及时释放局部引用
    }

    // 4. 转换Java Observation列表为C结构体数组
    LOGI("转换Java Observation列表为C结构体数组");
    Observation* obsArray = (Observation*)malloc(size * sizeof(Observation));
    if (obsArray == nullptr) {
        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"),
                      "观测数据数组内存分配失败");
        LOGE("观测数据数组内存分配失败");
        free(controlPoints);
        env->DeleteLocalRef(pointClass);
        return nullptr;
    }

    // 4.1 获取Kotlin Observation类信息
    jclass obsClass = env->FindClass("com/auto/survey/activity/geosurv/backward/entity/Observation");
    if (obsClass == nullptr) {
        env->ThrowNew(env->FindClass("java/lang/ClassNotFoundException"),
                      "Observation类未找到");
        LOGE("Observation类未找到");
        free(controlPoints);
        free(obsArray);
        env->DeleteLocalRef(pointClass);
        return nullptr;
    }

    jfieldID obsPointIdField = env->GetFieldID(obsClass, "point_id", "I");
    jfieldID obsAngleField = env->GetFieldID(obsClass, "angle", "D");
    jfieldID obsDistanceField = env->GetFieldID(obsClass, "distance", "D");
    jfieldID obsAzimuthField = env->GetFieldID(obsClass, "azimuth", "D");


    if (obsPointIdField == nullptr || obsAngleField == nullptr) {
        env->ThrowNew(env->FindClass("java/lang/NoSuchFieldError"),
                      "Observation类字段未找到");
        LOGE("Observation类字段未找到");
        free(controlPoints);
        free(obsArray);
        env->DeleteLocalRef(pointClass);
        env->DeleteLocalRef(obsClass);
        return nullptr;
    }



    // 4.2 填充观测数据
    for (int i = 0; i < size; i++) {
        jobject obsObj = env->CallObjectMethod(observations, listGet, i);
        if (obsObj == nullptr) {
            env->ThrowNew(env->FindClass("java/lang/IndexOutOfBoundsException"),
                          "观测数据列表访问越界");
            LOGE("观测数据列表访问越界");
            free(controlPoints);
            free(obsArray);
            env->DeleteLocalRef(pointClass);
            env->DeleteLocalRef(obsClass);
            return nullptr;
        }



        obsArray[i].point_id = env->GetIntField(obsObj, obsPointIdField);
        obsArray[i].angle = env->GetDoubleField(obsObj, obsAngleField);
        obsArray[i].distance = env->GetDoubleField(obsObj, obsDistanceField);
        obsArray[i].azimuth = env->GetDoubleField(obsObj, obsAzimuthField);

        LOGI("#########################################");
        LOGI("obsArray，point_id: %d", obsArray[i].point_id);
        LOGI("obsArray，angle: %f",obsArray[i].angle);
        LOGI("obsArray，distance: %f", obsArray[i].distance);
        LOGI("obsArray，azimuth: %f", obsArray[i].azimuth);

        env->DeleteLocalRef(obsObj); // 及时释放局部引用
    }

    // 5. 调用C语言核心计算函数
    LOGI("调用C语言核心计算函数");
    CalculationResult result = calculate_resection(controlPoints, obsArray, size);

    // 6. 创建Java返回对象
    // 6.1 创建测站位置Point对象（复用之前查找的pointClass）
    jmethodID pointConstructor = env->GetMethodID(pointClass, "<init>", "(DDD)V");

    LOGI("calculate_resection，position.x: %f", result.position.x);
    LOGI("calculate_resection，position.y: %f",result.position.y);
    LOGI("calculate_resection，position.z: %f", result.position.z);
    LOGI("calculate_resection，error_x: %f", result.error_x);
    LOGI("calculate_resection，error_y: %f", result.error_y);
    LOGI("calculate_resection，iterations: %d", result.iterations);
    LOGI("calculate_resection，success: %d", result.success);

    jobject stationObj = env->NewObject(
            pointClass, pointConstructor,
            result.position.x,
            result.position.y,
            result.position.z
    );

    // 6.2 创建CalculationResult对象
    jclass resultClass = env->FindClass("com/auto/survey/activity/geosurv/backward/entity/CalculationResult");
    if (resultClass == nullptr) {
        env->ThrowNew(env->FindClass("java/lang/ClassNotFoundException"),
                      "CalculationResult类未找到");
        LOGE("CalculationResult类未找到");
        free(controlPoints);
        free(obsArray);
        env->DeleteLocalRef(pointClass);
        env->DeleteLocalRef(obsClass);
        if (stationObj != nullptr) env->DeleteLocalRef(stationObj);
        return nullptr;
    }

    // 验证类是否正确（添加额外检查）
    jclass classClass = env->GetObjectClass(resultClass);
    jmethodID getNameMethod = env->GetMethodID(classClass, "getName", "()Ljava/lang/String;");
    jstring className = (jstring)env->CallObjectMethod(resultClass, getNameMethod);
    const char* classNameStr = env->GetStringUTFChars(className, nullptr);
    LOGI("找到的CalculationResult类名: %s", classNameStr);
    env->ReleaseStringUTFChars(className, classNameStr);
    env->DeleteLocalRef(className);
    env->DeleteLocalRef(classClass);



// 获取带参构造函数ID（关键修改）
    jmethodID resultConstructor = env->GetMethodID(
            resultClass,
            "<init>",
            "(Lcom/auto/survey/activity/geosurv/backward/entity/Point;DDDII)V"
    );
    if (resultConstructor == nullptr) {
        // 尝试获取异常信息
        jthrowable exception = env->ExceptionOccurred();
        if (exception) {
            LOGE("尝试获取异常信息，exception");
            env->ExceptionDescribe();
            env->ExceptionClear();
        }
        LOGE("无法获取CalculationResult构造函数，签名可能错误");

        // 释放资源...
        free(controlPoints);
        free(obsArray);
        env->DeleteLocalRef(pointClass);
        env->DeleteLocalRef(obsClass);
        env->DeleteLocalRef(resultClass);
        env->DeleteLocalRef(stationObj);
        return nullptr;
    } else {
        LOGI("成功获取CalculationResult构造函数");
    }


    // 直接通过构造函数初始化所有字段（无需后续SetField）
    jobject resultObj = env->NewObject(
            resultClass,
            resultConstructor,
            stationObj,               // station: Point
            result.error_x,           // error_x: Double
            result.error_y,           // error_y: Double
            result.error_rms,         // error_rms: Double
            result.iterations,        // iterations: Int
            result.success            // success: Int
    );


    // 验证 CalculationResult 类中的 station 字段是否存在
    jmethodID getDeclaredFields = env->GetMethodID(
            env->FindClass("java/lang/Class"),
            "getDeclaredFields",
            "()[Ljava/lang/reflect/Field;"
    );
    jobjectArray fields = (jobjectArray)env->CallObjectMethod(resultClass, getDeclaredFields);
    jsize fieldCount = env->GetArrayLength(fields);
    LOGI("CalculationResult 类共有 %d 个字段", fieldCount);

    env->DeleteLocalRef(fields);

    LOGI("填充结果字段");
    // 6.3 填充结果字段
    jfieldID stationField = env->GetFieldID(resultClass, "station", "Lcom/auto/survey/activity/geosurv/backward/entity/Point;");
    if (stationField == nullptr) {
        LOGE("stationField 为 null，字段名或类型错误");
        // 释放资源后返回
        free(controlPoints);
        free(obsArray);
        env->DeleteLocalRef(pointClass);
        env->DeleteLocalRef(obsClass);
        env->DeleteLocalRef(resultClass);
        env->DeleteLocalRef(stationObj);
        return nullptr;
    }

    LOGI("000000000000000");
    jfieldID errorXField = env->GetFieldID(resultClass, "errorX", "D");
    LOGI("11111111111111");
    jfieldID errorYField = env->GetFieldID(resultClass, "errorY", "D");
    LOGI("2222222222222");
    jfieldID errorRmsField = env->GetFieldID(resultClass, "errorRMS", "D");
    LOGI("3333333333333");
    jfieldID iterationsField = env->GetFieldID(resultClass, "iterations", "I");
    LOGI("4444444444");
    jfieldID successField = env->GetFieldID(resultClass, "success", "I");
    LOGI("5555555555");

    env->SetObjectField(resultObj, stationField, stationObj);
    env->SetDoubleField(resultObj, errorXField, result.error_x);
    env->SetDoubleField(resultObj, errorYField, result.error_y);
    env->SetDoubleField(resultObj, errorRmsField, result.error_rms);
    env->SetIntField(resultObj, iterationsField, result.iterations);
    env->SetIntField(resultObj, successField, result.success);

    // 7. 释放资源
    free(controlPoints);
    free(obsArray);

    // 8. 释放JNI局部引用
    env->DeleteLocalRef(listClass);
    env->DeleteLocalRef(pointClass);
    env->DeleteLocalRef(obsClass);
    env->DeleteLocalRef(resultClass);
    env->DeleteLocalRef(stationObj);

    return resultObj;
}